/*
 * File name: cgi_client.c
 * Description: CGI code
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "cgi_common.h"
#include "crc32.h"

//#define CGI_DEBUG
#ifdef CGI_DEBUG
#define DEBUG(fmt, arg...) printf(fmt, ##arg)
#else
#define DEBUG(fmt, arg...)
#endif

int myisxdigit(char c)
{
	if ((c >= 48 && c <= 57) || (c >= 97 && c <= 102) || (c >= 65 && c <= 70))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void ConvertAllSpecialChars(char * src)
{
	char local[CGI_LINE_LENGTH] = {0};
	char tmp[10] = {0};
	int hex = 0;
	int i = 0;
	int index = 0;
	for (i = 0; i < strlen(src); ++i)
	{
		switch (src[i])
		{
		case '+':
			local[index++] = ' ';
			break;
		case '%':
			if (myisxdigit(src[i + 1]) && myisxdigit(src[i + 2]))
			{
				memcpy(tmp, src + i + 1, 2);
				hex = strtol(tmp, NULL, 16);
				if (hex == 0x20 || hex == 0x22 || hex == 0x23 || hex == 0x25 || hex == 0x26 || hex == 0x27 || hex == 0x2B || hex == 0x3C || hex == 0x3E)
				{
					local[index++] = (unsigned char)(hex & 0xFF);
					i += 2;
				}
				else local[index++] = '%';
			}
			else {
				local[index++] = '%';
			}
			break;
		default:
			local[index++] = src[i];
			break;
		}
	}

	bzero(src, CGI_LINE_LENGTH);
	strcpy(src, local);
}

int get_cgi_query_param(const char *data, const char *pattern, char *buf[], int buf_len)
{
	const char *p1 = data;
	const char *p2 = pattern;
	int i = 0, j = 0;
	while(*p1 && *p2)
	{
		if(*p1 == *p2)
		{
			if(*p2 == '&')
			{
				DEBUG("query param: [%02d] %s\n", i, buf[i]);
				i++;				
				j = 0;

				if(i >= buf_len)
					return -1;
			}
			p1++;
			p2++;
		}
		else
		{
			if(*p2 != '&')
			{
				return -2;
			}
			buf[i][j++] = *p1;
			p1++;
		}
	}

	if(i != buf_len - 1)
		return -3;

	DEBUG("query param: [%02d] %s end\n", i, buf[i]);
	return 0;
}

static int snd_buff_add_int(unsigned char * buf, int * index, int val)
{
	int i = *index;
	if(i + 4 >= CGI_PACK_MAX_LEN - CGI_PACK_CRC_LEN)
		return 0;

	unsigned int value = (unsigned int)val;
	buf[i++] = (value & 0xFF000000) >> 24;
	buf[i++] = (value & 0x00FF0000) >> 16;
	buf[i++] = (value & 0x0000FF00) >> 8;
	buf[i++] = value & 0x000000FF;
	DEBUG("sndbuf add int: %d\n", value);
	*index = i;
	return 1;
}

static int recv_buff_get_int(unsigned char * buf, int buf_len, int * index, int * val)
{
	int i = *index;
	if(i + 4 > buf_len - CGI_PACK_CRC_LEN)
		return 0;

	unsigned int value = 0;
	value += (unsigned int)buf[i++] << 24;
	value += (unsigned int)buf[i++] << 16;
	value += (unsigned int)buf[i++] << 8;
	value += (unsigned int)buf[i++];
	DEBUG("recvbuf get int: %d\n", value);
	*index = i;
	*val = (int)value;
	return 1;
}


static int snd_buff_add_str(unsigned char * buf, int * index, char * str)
{
	int i = *index;
	int len = strlen(str);
	if(i + 1 + len >= CGI_PACK_MAX_LEN - CGI_PACK_CRC_LEN)
		return 0;

	buf[i++] = len;
	memcpy(buf + i, str, len);
	i += len;
	DEBUG("sndbuf add str: %s\n", str);
	*index = i;
	return 1;
}

static int recv_buff_get_str(unsigned char * buf, int buf_len, int * index, char * str, int str_len)
{
	int i = *index;
	if(i + 1 > buf_len - CGI_PACK_CRC_LEN)
		return 0;
	int len = buf[i++];
	if(i + len > buf_len - CGI_PACK_CRC_LEN || len >= str_len)
		return 0;

	memset(str, '\0', str_len);
	memcpy(str, (char *)buf + i, len);
	i += len;
	DEBUG("recvbuf get str: %s\n", str);
	*index = i;
	return 1;
}



typedef struct cgi_Name_t
{
	const char *prog_name;
	int cmd;
	int ret_cmd;
	const char *input_param_pattern;
	int input_param_cnt;
}cgiName;

cgiName g_cgi_prog_array[] = {
	{
		"setConfigure.cgi",
		CGI_CMD_SET_CONFIGURE,
		CGI_CMD_SET_CONFIGURE_RET,
		"InputSource=&IPRecvMode=&IPPort=&IPMulticastAddr=&IPUnicastAddr=&RTSPAddress=&"
		"SRTMode=&SRTCallerAddr=&SRTPort=&SRTLatency=&SRTEncrypt=&SRTPassword=&"
		"Fmt=&Gdrmode=&Gop=&Mode=&kvm_bitrate=&framerate=&height=&width=&audioswitch=&",
		21,
	},
	{
		"getNetwork.cgi",
		CGI_CMD_GET_NETWORK,
		CGI_CMD_GET_NETWORK_RET,
		"",
		0,
	},
	{
		"setNetwork.cgi",
		CGI_CMD_SET_NETWORK,
		CGI_CMD_SET_NETWORK_RET,
		"Addressing=&CtrlIP=&CtrlMask=&StreamIP=&StreamMask=&StreamGateway=&",
		6,
	},
	{
		"ClearAlarmInfo.cgi",
		CGI_CMD_CLEAR_ALARM_INFO,
		CGI_CMD_CLEAR_ALARM_INFO_RET,
		"",
		0,
	},
	{
		"LoadDefault.cgi",
		CGI_CMD_LOAD_DEFAULT,
		CGI_CMD_LOAD_DEFAULT_RET,
		"",
		0,
	},
	{
		"Login.cgi",
		CGI_CMD_LOGIN,
		CGI_CMD_LOGIN_RET,
		"Username=&Password=&",
		2,
	},
	{
		"ApplyAccount.cgi",
		CGI_CMD_APPLY_ACCOUNT,
		CGI_CMD_APPLY_ACCOUNT_RET,
		"Password=&",
		1,
	},
	{
		"PingTest.cgi",
		CGI_CMD_PING_TEST,
		CGI_CMD_PING_TEST_RET,
		"address=&",
		1,
	},
	{
		"getConfigure.cgi",
		CGI_CMD_GET_CONFIGURE,
		CGI_CMD_GET_CONFIGURE_RET,
		"",
		0,
	},
	{
		"getDevice.cgi",
		CGI_CMD_GET_DEVICE,
		CGI_CMD_GET_DEVICE_RET,
		"",
		0,
	},
	{
		"getSystem.cgi",
		CGI_CMD_GET_SYSTEM,
		CGI_CMD_GET_SYSTEM_RET,
		"",
		0,
	},
	{
		"getTemperature.cgi",
		CGI_CMD_GET_TEMPERATURE,
		CGI_CMD_GET_TEMPERATURE_RET,
		"",
		0,
	},
	{
		"getStatus.cgi",
		CGI_CMD_GET_STATUS,
		CGI_CMD_GET_STATUS_RET,
		"",
		0,
	},
	{
		"getAlarmInfo.cgi",
		CGI_CMD_GET_ALARM_INFO,
		CGI_CMD_GET_ALARM_INFO_RET,
		"",
		0,
	},
	{
		"getPingAddress.cgi",
		CGI_CMD_GET_PING_ADDR,
		CGI_CMD_GET_PING_ADDR_RET,
		"",
		0,
	},
	{
		"ApplyWifi.cgi",
		CGI_CMD_APPLY_WIFI,
		CGI_CMD_APPLY_WIFI_RET,
		"WifiSwitch=&Wifiname=&Wifipasswd=&",
		3,
	},
};

int main(int argc, char *argv[])
{
	int cmd = CGI_CMD_NOT_SUPPORT;
	int ret_cmd = 0;
	int param_cnt = 0;
	const char *param_pattern = NULL;
	char *param_buf = NULL;
	char **param = NULL;
	char *print_buf = NULL;
	int socket_fd = 0;
	int ret = 0;
	int snd_len = 0;
	int recv_len = 0;
	int length = 0;

	unsigned char snd_buff[CGI_PACK_MAX_LEN] = {0};
	unsigned char recv_buff[CGI_PACK_MAX_LEN] = {0};

	int snd_index = CGI_PACK_LEAST_LEN - CGI_PACK_CRC_LEN;
	int recv_index = CGI_PACK_LEAST_LEN - CGI_PACK_CRC_LEN;
	int value = 0;
	int value_tmp = 0;
	char rtspaddr[CGI_COMMON_LEN] = { 0 };
	char addr[CGI_IP_LEN] = {0};
	char addr_tmp[CGI_IP_LEN] = {0};
	char passwd[CGI_PASSWORD_LEN] = {0};
	char passwd_tmp[CGI_PASSWORD_LEN] = {0};
	char device_name[CGI_IP_LEN] = {0};
	char string[CGI_IP_LEN] = {0};
	char alarm_info[ALARM_INFO_COL_NUMBER] = {0};
	char ping_buf[ALARM_INFO_COL_NUMBER] = {0};
	char ntp_addr[CGI_COMMON_LEN] = {0};
	char wifiname[CGI_COMMON_LEN] = { 0 };
	char wifipasswd[CGI_COMMON_LEN] = { 0 };
	gen_crc32_table();

	printf("Content type: text/html\n\n"); 

	//1.get cmd according to argv[0]
	for(int i = 0; i < sizeof(g_cgi_prog_array) / sizeof(cgiName); i++)
	{
		cgiName *prog = &g_cgi_prog_array[i];
		if(strstr(argv[0], prog->prog_name) != NULL)
		{
			cmd = prog->cmd;
			ret_cmd = prog->ret_cmd;
			param_cnt = prog->input_param_cnt;
			param_pattern = prog->input_param_pattern;
		}
	}
	DEBUG("cmd:0x%04x, param_cnt:%d, param_pattern:%s\n", cmd, param_cnt, param_pattern);
	if(cmd == CGI_CMD_NOT_SUPPORT)
	{
		printf("Command not support!");
		goto Fail;
	}

	//2.get all param and add to sndbuf according to cmd
	if(param_cnt != 0)
	{
		//alloc buffer for param
		param_buf = (char *)malloc(param_cnt * sizeof(char *) + param_cnt * CGI_LINE_LENGTH);
		if(param_buf == NULL)
		{
			printf("Out of memory!");
			goto Fail;
		}
		param = (char **)param_buf;
		char *p = param_buf + param_cnt * sizeof(char *);
		for(int i = 0; i < param_cnt; i++)
		{
			param[i] = p;
			p += CGI_LINE_LENGTH;
		}

		//get param string
		char *data = getenv("QUERY_STRING");
		if(data == NULL)
		{
			printf("Lack of parameter!");
			goto Fail;
		}
		DEBUG("data:%s\n", data);

		ret = get_cgi_query_param(data, param_pattern, param, param_cnt);
		if(ret < 0)
		{
			printf("Wrong parameter! ret:%d", ret);
			goto Fail;
		}

		//add to sndbuf
		ret = 1;
		int i = 0;
		int pid = 0;
		switch(cmd)
		{
		case CGI_CMD_SET_CONFIGURE:
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			//ip mode
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			//srt mode
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			//decoder param
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			break; 

		case CGI_CMD_SET_NETWORK:
			//addressing
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			//ctrl ip
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			
			//stream ip
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			break;

		case CGI_CMD_LOGIN:
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			break;

		case CGI_CMD_APPLY_ACCOUNT:
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			break;

		case CGI_CMD_PING_TEST:
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			break;
		case CGI_CMD_APPLY_WIFI:
			ret &= snd_buff_add_int(snd_buff, &snd_index, atoi(param[i++]));
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			ret &= snd_buff_add_str(snd_buff, &snd_index, param[i++]);
			break;
		default:
			break;
		}

		if(ret == 0 || i != param_cnt)
		{
			printf("Error when add sndbuf! ret:%d i:%d param_cnt:%d");
			goto Fail;
		}
	}

	//3.send request and recv response
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_fd < 0)
	{
		printf("socket fail");
		goto Fail;
	}

	struct sockaddr_in send_addr;
	bzero(&send_addr, sizeof(send_addr));
	send_addr.sin_family = AF_INET;
	send_addr.sin_port = htons(CGI_INTF_PORT);
	send_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	if(0 != connect(socket_fd, (struct sockaddr*)&send_addr, sizeof(send_addr)))
	{
		printf("connect fail");
		goto Fail;
	}

	snd_len = snd_index + CGI_PACK_CRC_LEN;
	snd_buff[0] = CGI_PACK_HEAD_1;
	snd_buff[1] = CGI_PACK_HEAD_2;
	snd_buff[2] = CGI_PACK_HEAD_3;
	snd_buff[3] = CGI_PACK_VERSION;
	snd_buff[4] = (snd_len & 0xFF00) >> 8;
	snd_buff[5] = snd_len & 0x00FF;
	snd_buff[6] = (cmd & 0xFF00) >> 8;
	snd_buff[7] = cmd & 0x00FF;
	crc32_calc((char *)snd_buff, snd_len - 4, (char *)&(snd_buff[snd_len - 4]));

	if (snd_len != send(socket_fd, snd_buff, snd_len, 0))
	{
		printf("send fail");
		goto Fail;
	}

	while (1)
	{
		memset(recv_buff, '\0', CGI_PACK_MAX_LEN);
		ret = recv(socket_fd, recv_buff, CGI_PACK_MAX_LEN, MSG_DONTWAIT | MSG_WAITALL);
		if (ret <= 0)
		{
			if (ret < 0 && errno == EWOULDBLOCK)
			{
				usleep(10 * 1000);
				continue;
			}
			if (ret == 0)
			{
				usleep(10 * 100);
				continue;
			}
			printf("recv fail! ret:%d errno:%d", ret, errno);
			goto Fail;
		}
		else
		{
			if (ret < CGI_PACK_LEAST_LEN)
			{
				ret = recv(socket_fd, recv_buff + ret, CGI_PACK_MAX_LEN - ret, MSG_WAITALL);
			}
	
			if (recv_buff[0] != CGI_PACK_HEAD_1 || recv_buff[1] != CGI_PACK_HEAD_2 || recv_buff[2] != CGI_PACK_HEAD_3)
			{
				printf("head fail");
				goto Fail;
			}
			int version = recv_buff[3];
			if (version > CGI_PACK_VERSION)
			{
				printf("version fail");
				goto Fail;
			}
	
			recv_len = (unsigned short)recv_buff[5] + ((unsigned short)recv_buff[4] << 8);
			if (recv_len != ret)
			{
				printf("length fail, ret:%d p_len:%d", ret, recv_len);
				goto Fail;
			}
			unsigned char crc[4] = {0};
			crc32_calc((char *)recv_buff, ret, (char *)crc);
			if (crc[0] != 0 || crc[1] != 0 || crc[2] != 0 || crc[3] != 0)
			{
				printf("crc fail");
				goto Fail;
			}
			int p_cmd = (unsigned short)recv_buff[7] + ((unsigned short)recv_buff[6] << 8);
			if (p_cmd != ret_cmd)
			{
				printf("ret_cmd fail, ret_cmd:0x%04x p_cmd:0x%04x", ret_cmd, p_cmd);
				goto Fail;
			}			
			break;
		}
	}

	print_buf = (char *)malloc(CGI_PACK_MAX_LEN);
	if(print_buf == NULL)
	{
		printf("Out of memory!");
		goto Fail;
	}
	int offset = 0;
	int i = 0;
	int count = 0;
	ret = 1;
	switch(ret_cmd)
	{
	case CGI_CMD_SET_NETWORK_RET:
	case CGI_CMD_SET_CONFIGURE_RET:
	case CGI_CMD_LOAD_DEFAULT_RET:
	case CGI_CMD_CLEAR_ALARM_INFO_RET:
	case CGI_CMD_APPLY_ACCOUNT_RET:
	case CGI_CMD_APPLY_WIFI_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "OK");
		break;

	case CGI_CMD_LOGIN_RET:
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "%s", value == 1 ? "OK" : "Fail");
		break;

	case CGI_CMD_PING_TEST_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PingInfoDetails>\n");
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, ping_buf, ALARM_INFO_COL_NUMBER);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<CurrentPing>%s</CurrentPing>\n", ping_buf);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</PingInfoDetails>\n");
		break;
		
	case CGI_CMD_GET_CONFIGURE_RET:
		//4.get param from recvbuf and output in xml format
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<ConfigureDetails>\n");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<InputSource>%d</InputSource>\n", value);
		//ip mode
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<IPRecvMode>%d</IPRecvMode>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<IPPort>%d</IPPort>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<IPMulticastAddr>%s</IPMulticastAddr>\n", addr);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<IPUnicastAddr>%s</IPUnicastAddr>\n", addr); 
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, rtspaddr, CGI_COMMON_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<RTSPAddress>%s</RTSPAddress>\n", rtspaddr);
		//SRT
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTMode>%d</SRTMode>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTCallerAddr>%s</SRTCallerAddr>\n", addr);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTPort>%d</SRTPort>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTLatency>%d</SRTLatency>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTEncrypt>%d</SRTEncrypt>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, passwd, CGI_PASSWORD_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<SRTPassword>%s</SRTPassword>\n", passwd);
		//Param
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Fmt>%d</Fmt>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Gdrmode>%d</Gdrmode>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Gop>%d</Gop>\n", value); 
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Mode>%d</Mode>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<kvm_bitrate>%d</kvm_bitrate>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<framerate>%d</framerate>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<height>%d</height>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<width>%d</width>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<audioswitch>%d</audioswitch>\n", value);
		
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</ConfigureDetails>\n");
		break;
	case CGI_CMD_GET_NETWORK_RET:
		//4.get param from recvbuf and output in xml format
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<NetworkDetails>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PortDetails>\n");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Addressing>%d</Addressing>\n", value);
		for (i = 0; i < 2; i++)
		{
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Port>\n");

			ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<MAC>%s</MAC>\n", addr);

			ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<IP>%s</IP>\n", addr);

			
			ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Subnet>%s</Subnet>\n", addr);

			ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Gateway>%s</Gateway>\n", addr);
			
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</Port>\n");
		}
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</PortDetails>\n");
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, addr, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PingAddr>%s</PingAddr>\n", addr);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</NetworkDetails>\n");
		break;
	case CGI_CMD_GET_DEVICE_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, device_name, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<DeviceDetails>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Device>Decoder</Device>");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<DeviceShow>%s</DeviceShow>\n", device_name);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</DeviceDetails>\n");
		break;
	case CGI_CMD_GET_SYSTEM_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<SystemDetails>\n");
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<FirmwareVersion>%s</FirmwareVersion>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<FPGAVersion>%s</FPGAVersion>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<SerialNo>%s</SerialNo>\n", string);

		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<WifiSwitch>%d</WifiSwitch>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, wifiname, CGI_COMMON_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<WifiName>%s</WifiName>\n", wifiname);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, wifipasswd, CGI_COMMON_LEN);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<WifiPasswd>%s</WifiPasswd>\n", wifipasswd);

		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</SystemDetails>\n");
		break;
	case CGI_CMD_GET_TEMPERATURE_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StatusDetails>\n");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Temperature>%d</Temperature>\n", value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</StatusDetails>\n");
		break;
	case CGI_CMD_GET_STATUS_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StatusDetails>\n");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StatusTotalBitrate>%d</StatusTotalBitrate>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf + offset, CGI_PACK_MAX_LEN - offset, "<Temperature>%d</Temperature>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PMTPID>0x%04x</PMTPID>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PCRPID>0x%04x</PCRPID>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<VideoPID>0x%04x</VideoPID>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Audio1PID>0x%04x</Audio1PID>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<VideoFormat>%s</VideoFormat>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StatusAudioCodec>%s</StatusAudioCodec>\n", string);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Audio1Rate>%d</Audio1Rate>\n", value);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Chrome>%s</Chrome>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<RateMode>%s</RateMode>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StatusInputSource>%s</StatusInputSource>\n", string);
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, string, CGI_IP_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<DecodingState>%s</DecodingState>\n", string);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</StatusDetails>\n");
		break;
	case CGI_CMD_GET_CURRENT_INFO_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<StreamInfo>\n");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Bitrate>%d</Bitrate>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Connected>%s</Connected>\n", value ? "Connected" : "Disconnect");
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PacketLoss>%d</PacketLoss>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PacketDrop>%d</PacketDrop>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<UsedBandwidth>%d</UsedBandwidth>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<MsRTT>%d</MsRTT>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<MsBuf>%d</MsBuf>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<MsLatency>%d</MsLatency>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Uptime>%d</Uptime>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Reconnect>%d</Reconnect>\n", value);
		ret &= recv_buff_get_int(recv_buff, recv_len, &recv_index, &value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Lossrate>%d</Lossrate>\n", value);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</StreamInfo>\n");
		break;
	case CGI_CMD_GET_ALARM_INFO_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<AlarmInfoDetails>\n");
		for (i = 0; i < ALARM_INFO_LINE_NUMBER; i++)
		{
			ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, alarm_info, ALARM_INFO_COL_NUMBER);
			length = strlen(alarm_info);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<AlarmInfoLineLen>%d</AlarmInfoLineLen>\n", length);
			offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<AlarmInfoLineStr>%s</AlarmInfoLineStr>\n", alarm_info);
		}
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</AlarmInfoDetails>\n");
		break;
	case CGI_CMD_GET_PING_ADDR_RET:
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<?xml version=\"1.0\"?>\n");
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<PingDetails>\n");
		ret &= recv_buff_get_str(recv_buff, recv_len, &recv_index, ntp_addr, CGI_COMMON_LEN);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "<Address>%s</Address>\n", ntp_addr);
		offset += snprintf(print_buf+offset, CGI_PACK_MAX_LEN-offset, "</PingDetails>\n");
		break;
	default:
		break;
	}

	if(ret == 0)
	{
		printf("Error when get recvbuf!");
		goto Fail;
	}

	printf("%s", print_buf);

Fail:
	if(socket_fd != 0)
	{
		close(socket_fd);
	}
	param = NULL;
	if(param_buf != NULL)
	{
		free(param_buf);
		param_buf = NULL;
	}
	if(print_buf == NULL)
	{
		free(print_buf);
		print_buf = NULL;
	}

	return 0;
}
